package com.gitee.wsl.text.regex

import com.gitee.wsl.ext.any.ifNullValue
import com.gitee.wsl.text.regex.BaseRegexPart.Companion.escape

 fun interface RegexPart {
    fun regexStr():String

    fun toRegex() = regexStr().toRegex()

     companion object{

         val anyChar = BaseRegexPart(".")

         val digitChar = BaseRegexPart("\\d")

         val digit = BaseRegexPart("\\d+")

         val noDigitChar = BaseRegexPart("\\D")

         val noDigit = BaseRegexPart("\\D+")

         val letter = BaseRegexPart("[[:alpha:]]")

         val alphaNumeric = BaseRegexPart("[A-Za-z0-9]")

         val whitespace= BaseRegexPart("\\s")

         val wordBoundary= BaseRegexPart("\\b")

         val wordChar= BaseRegexPart("\\w")

         val word= BaseRegexPart("\\w+")

         val noWordChar= BaseRegexPart("\\W")

         val noWord= BaseRegexPart("\\W+")

         val startOf= BaseRegexPart("^")

         val endOf= BaseRegexPart("$")

         fun anyOf(vararg terms: String) = BaseRegexPart(terms.joinToString("|", "(?:", ")") { Regex.escape(it) })

         fun anyOf(vararg terms: RegexPart) = BaseRegexPart(terms.joinToString("|", "(?:", ")") {it.regexStr()})

         fun oneOf(vararg terms: RegexPart) = BaseRegexPart(terms.joinToString("|", "[", "]") {it.regexStr()})

         fun <T : Comparable<T>> oneOf(range: ClosedRange<T>) = BaseRegexPart("${range.start}-${range.endInclusive}")

         fun literally(s: String) = BaseRegexPart(Regex.escape(s))
     }
}


open class BaseRegexPart(val part:String): RegexPart {

    override fun regexStr(): String = part

    override fun toString() = regexStr()

    companion object{

        /**
         * 正则中需要被转义的关键字
         */
        val RE_KEYS: Set<Char> = setOf(
            '$',
            '(', ')',
            '*', '+', '.',
            '[', ']',
            '?', '\\', '^',
            '{', '}',
            '|'
        )

        /**
         * 转义字符，将正则的关键字转义
         *
         * @param c 字符
         * @return 转义后的文本
         */
       internal fun escape(c: Char): String {
            val builder = StringBuilder()
            if (RE_KEYS.contains(c)) {
                builder.append('\\')
            }
            builder.append(c)
            return builder.toString()
        }

        /**
         * 转义字符串，将正则的关键字转义
         *
         * @param content 文本
         * @return 转义后的文本
         */
        internal fun escape(content: CharSequence): String {
            if (content.isBlank()) {
                return content.toString()
            }
            val builder = StringBuilder()
            val len = content.length
            var current: Char
            for (i in 0 until len) {
                current = content[i]
                if (RE_KEYS.contains(current)) {
                    builder.append('\\')
                }
                builder.append(current)
            }
            return builder.toString()
        }
    }

}

/**
 *  Kotlin 1.9
 */
fun RegexPart.group(name:String?=null): RegexPart {
    return BaseRegexPart(name.ifNullValue("($this)","""(?<$name>$this)"""))
}

fun RegexPart.zeroOrMore(): RegexPart {
    return BaseRegexPart("$this*")
}

fun RegexPart.oneOrMore(): RegexPart {
    return BaseRegexPart("$this+")
}

fun RegexPart.optional(): RegexPart {
    return BaseRegexPart("$this?")
}

fun RegexPart.beforeMust(part: RegexPart): RegexPart {
    return BaseRegexPart("(?=${part})$this")
}

fun RegexPart.beforeNotMust(part: RegexPart): RegexPart {
    return BaseRegexPart("(?!${part})$this")
}

fun RegexPart.afterMust(part: RegexPart): RegexPart {
    return BaseRegexPart("(?>=${part})$this")
}

fun RegexPart.afterNotMust(part: RegexPart): RegexPart {
    return BaseRegexPart("(?>!${part})$this")
}

fun RegexPart.repeat(range:IntRange): RegexPart {
    return BaseRegexPart("$this{${range.first},${range.last}}")
}

operator fun RegexPart.plus(factor: RegexPart): RegexPart {
    return BaseRegexPart("$this$factor")
}

operator fun RegexPart.plus(factor: String): RegexPart {
    return BaseRegexPart("$this${escape(factor)}")
}


operator fun RegexPart.plus(factor: Char): RegexPart {
    return BaseRegexPart("$this${escape(factor)}")
}

operator fun Char.plus(factor: RegexPart): RegexPart {
    return BaseRegexPart("${escape(this)}$factor")
}

operator fun RegexPart.times(factor: Int): RegexPart {
    return BaseRegexPart("$this{$factor}")
}

operator fun RegexPart.times(factor: IntRange): RegexPart {
    return repeat(factor)
}

operator fun RegexPart.not(): RegexPart {
    return BaseRegexPart("[^${this}]")
}


